package com.tiny.tinyweb.core.utils;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.util.ObjectUtils;

import com.tiny.tinyweb.core.dao.entity.MapEntity;

/**
 * java对象转换为格式化字符串的支持类。
 *
 * @see {@link org.springframework.core.style.DefaultValueStyler}
 * @author wxiaobin
 */
public class StringUtils {
    /**
     * 返回{@link java.lang.Object}的字符串表示。
     *
     * @param obj 需要字符串化的对象
     * @return 指定对象的字符串表示
     */
    @SuppressWarnings("unchecked")
    public static String toString(Object obj) {
        // null --> ""
        if (obj == null) {
            return "";
        }
        // class --> full class name
        if (obj instanceof Class) {
            return ((Class<?>) obj).getName();
        }
        // method --> class full name.method name()
        if (obj instanceof Method) {
            Method method = (Method) obj;
            return method.getDeclaringClass().getName() + "." + method.getName() + "()";
        }
        // MapEntity --> result of override 'toString' method
        if (obj instanceof MapEntity) {
            return obj.toString();
        }
        // Map --> class name@hash code[key1=entry1,key2=entry2,...]
        if (obj instanceof Map) {
            return toString((Map<Object, Object>) obj);
        }
        // Map.Entry --> class name@hash code[key1=entry1,key2=entry2,...]
        if (obj instanceof Map.Entry) {
            return toString((Map.Entry<Object, Object>) obj);
        }
        // Collection --> class name@hash code[item1,item2,...]
        if (obj instanceof Collection) {
            return toString((Collection<Object>) obj);
        }
        // array --> array<array type class name>@hash code[item1,item2,...]
        if (obj.getClass().isArray()) {
            return toString(ObjectUtils.toObjectArray(obj));
        }
        // others
        return String.valueOf(obj);
    }

    /**
     * 返回{@link java.util.Map}的字符串表示，样式：class name@hash code[key1=entry1,key2=entry2,...]。
     *
     * @param obj 需要字符串化的{@link java.util.Map}对象
     * @return 指定的{@link java.util.Map}对象的字符串表示
     */
    public static String toString(Map<Object, Object> obj) {
        if (obj == null) {
            return "";
        }
        StringBuilder result = new StringBuilder(obj.size() * 8 + 16);
        result.append(obj.getClass().getName() + "@"
                + Integer.toHexString(System.identityHashCode(obj)));
        if (obj.isEmpty()) {
            result.append("[empty]");
        } else {
            result.append("[");
            for (Iterator<Entry<Object, Object>> it = obj.entrySet().iterator(); it.hasNext();) {
                result.append(toString(it.next()));
                if (it.hasNext()) {
                    result.append(',');
                }
            }
            result.append("]");
        }
        return result.toString();
    }

    /**
     * 返回{@link java.util.Map.Entry}的字符串表示，样式：class name@hash code[key1=entry1,key2=entry2,...]。
     *
     * @param obj 需要字符串化的{@link java.util.Map.Entry}对象
     * @return 指定的{@link java.util.Map.Entry}对象的字符串表示
     */
    public static String toString(Map.Entry<Object, Object> obj) {
        if (obj == null) {
            return "";
        }
        return new ToStringBuilder(obj, ToStringStyle.SHORT_PREFIX_STYLE).append(
                String.valueOf(obj.getKey()), obj.getValue()).toString();
    }

    /**
     * 返回{@link java.util.Collection}的字符串表示，样式：class name@hash code[item1,item2,...]。
     *
     * @param obj 需要字符串化的{@link java.util.Collection}对象
     * @return 指定的{@link java.util.Collection}对象的字符串表示
     */
    public static String toString(Collection<Object> obj) {
        if (obj == null) {
            return "";
        }
        StringBuilder result = new StringBuilder(obj.size() * 8 + 16);
        result.append(obj.getClass().getName() + "@"
                + Integer.toHexString(System.identityHashCode(obj)));
        if (obj.isEmpty()) {
            result.append("[empty]");
        } else {
            result.append("[");
            for (Iterator<Object> it = obj.iterator(); it.hasNext();) {
                result.append(toString(it.next()));
                if (it.hasNext()) {
                    result.append(',');
                }
            }
            result.append("]");
        }
        return result.toString();
    }

    /**
     * 返回数组对象的字符串表示，样式：array<array type class name>@hash code[item1,item2,...]。
     *
     * @param obj 需要字符串化的数组对象
     * @return 指定的数组对象的字符串表示
     */
    public static String toString(Object[] obj) {
        if (obj == null) {
            return "";
        }
        StringBuilder result = new StringBuilder(obj.length * 8 + 16);
        result.append("array<");
        result.append(obj.getClass().getComponentType().getName());
        result.append(">@");
        result.append(Integer.toHexString(System.identityHashCode(obj)));
        if (obj.length > 0) {
            result.append("[");
            for (int i = 0; i < obj.length - 1; i++) {
                result.append(toString(obj[i]));
                result.append(',');
            }
            result.append(toString(obj[obj.length - 1]));
            result.append("]");
        } else {
            result.append("[empty]");
        }
        return result.toString();
    }
}
